# 游戏关卡
from ..components import info
import pygame
from .. import tools, setup
from .. import constants as C
from .. components import player, stuff, brick, box, enemy,coin
import os
import json

class Level:
    def start(self, game_info):
        self.game_info = game_info
        self.finished = False
        self.next = 'game_over'
        self.info = info.Info('level', self.game_info)
        self.load_map_data()
        self.setup_background()
        self.setup_start_positions()
        self.setup_player()
        self.setup_ground_items()
        self.setup_bricks_and_boxes()
        self.setup_enemies()
        self.setup_checkpoints()
        self.setup_coins()


    def load_map_data(self):
        file_name = 'level_1.json'
        file_path = os.path.join('source/data/maps', file_name)
        with open(file_path) as f:
            self.map_data = json.load(f)

    def setup_background(self):
        self.image_name = self.map_data['image_name']
        self.background = setup.GRAPHICS[self.image_name]
        rect = self.background.get_rect()
        self.background = pygame.transform.scale(self.background, (int(rect.width * C.BG_MULTI),
                                                                   int(rect.height * C.BG_MULTI)))
        self.background_rect = self.background.get_rect()
        self.game_window = setup.SCREEN.get_rect()  # 代表滑动的游戏窗口
        self.game_ground = pygame.Surface((self.background_rect.width, self.background_rect.height))


    def setup_start_positions(self):
        self.positions = []
        for data in self.map_data['maps']:
            # 指定地图开始和结束以及玩家出生的坐标
            self.positions.append((data['start_x'], data['end_x'], data['player_x'], data['player_y']))
        self.start_x, self.end_x, self.player_x, self.player_y = self.positions[0]
        # player_y 马里奥脚所在的位置  player_x 马里奥相对于窗口的相对位置

    # 玩家初始化
    def setup_player(self):
        self.player = player.Player('mario')
        self.player.rect.x = self.game_window.x + self.player_x  # 马里奥相对于窗口的相对位置
        self.player.rect.bottom = self.player_y # 马里奥脚所在的位置

    def setup_ground_items(self):  # 通过json文件得到每个物品的坐标和大小
        self.ground_items_group = pygame.sprite.Group()  # 精灵组， 将实例化的物品放在一个组里
        for name in ['ground', 'pipe', 'step']:
            for item in self.map_data[name]:
                self.ground_items_group.add(stuff.Item(item['x'], item['y'], item['width'], item['height'], name))

    def setup_bricks_and_boxes(self):  # 砖块和宝箱
        self.brick_group = pygame.sprite.Group()
        self.box_group = pygame.sprite.Group()

        if 'brick' in self.map_data:
            for brick_data in self.map_data['brick']:
                x, y = brick_data['x'], brick_data['y']
                brick_type = brick_data['type']
                if 'brick_num' in brick_data:
                    pass
                else:
                    self.brick_group.add(brick.Brick(x, y, brick_type))
        if 'box' in self.map_data:
            for box_data in self.map_data['box']:
                x, y = box_data['x'], box_data['y']
                box_type = box_data['type']
                self.box_group.add(box.Box(x, y, box_type))
    def setup_coins(self):
        # self.ateCoin_group = pygame.sprite.Group()
        self.coin_group = pygame.sprite.Group()
        if 'coin' in self.map_data:
            for coin_data in self.map_data['coin']:
                x, y = coin_data['x'], coin_data['y']
                self.coin_group.add(coin.Coin(x, y))


    def setup_enemies(self):
        self.dying_group = pygame.sprite.Group()
        self.enemy_group = pygame.sprite.Group()
        self.enemy_group_dict = {}
        for enemy_group_data in self.map_data['enemy']:
            group = pygame.sprite.Group()
            for enemy_group_id, enemy_list in enemy_group_data.items():
                for enemy_data in enemy_list:
                    group.add(enemy.create_enemy(enemy_data))
                self.enemy_group_dict[enemy_group_id] = group

    def setup_checkpoints(self):
        self.checkpoint_group = pygame.sprite.Group()
        for item in self.map_data['checkpoint']:
            x, y, w, h = item['x'], item['y'], item['width'], item['height']
            checkpoint_type = item['type']
            enemy_groupid = item.get('enemy_groupid')
            self.checkpoint_group.add(stuff.Checkpoint(x, y, w, h, checkpoint_type, enemy_groupid))
    def game_clock(self):
        t = pygame.time.get_ticks()  # 该时间指的从pygame初始化后开始计算，到调用该函数为止
        self.game_info['time'] = int(300-t/1000)
        # pygame.display.flip()
    def update(self, surface, keys):
        self.current_time = pygame.time.get_ticks()
        self.player.update(keys)  # 调用马里奥的update方法
        # self.game_info['time'] -= int(self.current_time/1000)
        # self.add_coins()
        # self.game_clock()
        if self.player.dead:
            if self.current_time - self.player.death_timer > 3000:
                self.finished = True
                # self.game_clock()
        else:
            self.update_player_position()  # 传入键盘事件
            self.check_checkpoints()
            self.check_if_go_die()
            self.update_game_window()
            self.info.update()
            self.brick_group.update()
            self.box_group.update()
            self.enemy_group.update(self)
            self.dying_group.update(self)
            self.coin_group.update()
            # self.game_clock()

            # self.ateCoin_group.update()

        self.draw(surface)

    def update_player_position(self):  # 利用当前玩家的速度更新玩家的位置
        self.game_clock()
        # x方向
        # 不能走回头路
        self.player.rect.x += self.player.x_vel
        if self.player.rect.x >= 8505:
            self.finished = True
        if self.player.rect.x < self.start_x:
            self.player.rect.x = self.start_x

        elif self.player.rect.right > self.end_x:
            self.player.rect.right = self.end_x
        self.check_x_collisions()
        # y 方向
        if not self.player.dead:
            self.player.rect.y += self.player.y_vel
            self.check_y_collisions()

    # x方向撞到柱子、怪物
    def check_x_collisions(self):
        # 检查一个精灵是否与精灵组里的任何一个精灵有碰撞，返回第一个和马里奥碰撞的精灵，什么都没有就返回空
        check_group = pygame.sprite.Group(self.ground_items_group, self.brick_group, self.box_group)
        collided_sprite = pygame.sprite.spritecollideany(self.player, check_group)
        if collided_sprite:
            self.adjust_player_x(collided_sprite)

        enemy = pygame.sprite.spritecollideany(self.player, self.enemy_group)
        if enemy:
            self.player.go_die()

    # y方向上顶起砖块
    def check_y_collisions(self):
        check_group = pygame.sprite.Group(self.ground_items_group, self.brick_group, self.box_group)
        collided_sprite = pygame.sprite.spritecollideany(self.player, check_group)
        if collided_sprite:
            self.adjust_player_y(collided_sprite)

        enemy = pygame.sprite.spritecollideany(self.player, self.enemy_group)
        if enemy:
            self.enemy_group.remove(enemy)
            self.dying_group.add(enemy)
            if self.player.y_vel < 0:
                how = 'bumped'  # 向上顶起
            else:
                how = 'trampled'  # 向下踩踏
            enemy.go_die(how)

        coins = pygame.sprite.spritecollideany(self.player, self.coin_group)
        if coins:
            # self.coin_group.remove(coins)
            # self.ateCoin_group.add(coins)
            self.game_info['coin'] += 1
            self.game_info['score'] += 100
            coins.add_coins()
            # pygame.display.flip()
            # self.add_coins()

        self.check_will_fall(self.player)

    def adjust_player_x(self, sprite):
        if self.player.rect.x < sprite.rect.x:
            self.player.rect.right = sprite.rect.left
        else:
            self.player.rect.left = sprite.rect.right
        self.player.x_vel = 0

    def adjust_player_y(self, sprite):
        # downwards
        if self.player.rect.bottom < sprite.rect.bottom:
            self.player.y_vel = 0
            self.player.rect.bottom = sprite.rect.top
            self.player.state = 'walk'
        # upwards
        else:
            self.player.y_vel = 7
            self.player.rect.top = sprite.rect.bottom
            self.player.state = 'fall'

    def check_will_fall(self, sprite):
        sprite.rect.y += 1  # 坠落一个像素试探下方是否有障碍
        check_group = pygame.sprite.Group(self.ground_items_group,self.brick_group, self.box_group)
        collided_sprite = pygame.sprite.spritecollideany(sprite, check_group)
        if not collided_sprite and sprite.state != 'jump':  # 处于跳起状态时，不会发生坠落
            sprite.state = 'fall'
        sprite.rect.y -= 1

    def update_game_window(self):
        third = self.game_window.x + self.game_window.width / 3
        # 当Mario超过窗口的1/3时。窗口按照Mario的移动速度移动，且马里奥不能超过地图的末尾
        if self.player.x_vel > 0 and self.player.rect.centerx > third and self.game_window.right < self.end_x:
            self.game_window.x += self.player.x_vel
            self.start_x = self.game_window.x

    def draw(self, surface):
        self.game_ground.blit(self.background, self.game_window, self.game_window)
        self.game_ground.blit(self.player.image, self.player.rect)
        self.brick_group.draw(self.game_ground)
        self.box_group.draw(self.game_ground)
        self.enemy_group.draw(self.game_ground)
        self.dying_group.draw(self.game_ground)
        self.coin_group.draw(self.game_ground)
        # self.ateCoin_group.draw(self.game_ground)

        surface.blit(self.game_ground, (0, 0), self.game_window)  # 把背景图中滑动窗口所在位置的图片画到屏幕上
        self.info.draw(surface)
        # surface.fill((0, 255, 0))  # 绿色

    def check_checkpoints(self):
        checkpoint = pygame.sprite.spritecollideany(self.player, self.checkpoint_group)
        if checkpoint:
            if checkpoint.checkpoint_type == 0:
                # 一旦检查点被触达，就把该检查点对应的敌人放到该精灵组里
                self.enemy_group.add(self.enemy_group_dict[str(checkpoint.enemy_groupid)])
            checkpoint.kill()  # 如果检查点被触碰过，那么检查点销毁

    def check_if_go_die(self):
        # 判断Mario是否掉到屏幕外
        if self.player.rect.y > C.SCREEN_H:
            self.player.go_die()





